using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using ActiproSoftware.SyntaxEditor;
using ActiproSoftware.SyntaxEditor.Addons.Dynamic;

namespace WindowsUserControl.Codes {

	/// <summary>
	/// Represents a form for selecting a language definition to dynamically create.
	/// </summary>
	public class DynamicallyCreateForm : System.Windows.Forms.Form {

		private DynamicSyntaxLanguage language;

		//

		private System.Windows.Forms.Button cancelButton;
		private System.Windows.Forms.Button okButton;
		private System.Windows.Forms.Label headingLabel;
		private System.Windows.Forms.RadioButton loggingRadioButton;
		private System.Windows.Forms.RadioButton directiveXmlToCSharpRadioButton;
		private System.Windows.Forms.RadioButton scriptXmlToCSharpRadioButton;
	
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;
        /// <summary>
        /// 
        /// </summary>
		public DynamicallyCreateForm() {
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.cancelButton = new System.Windows.Forms.Button();
			this.okButton = new System.Windows.Forms.Button();
			this.loggingRadioButton = new System.Windows.Forms.RadioButton();
			this.headingLabel = new System.Windows.Forms.Label();
			this.directiveXmlToCSharpRadioButton = new System.Windows.Forms.RadioButton();
			this.scriptXmlToCSharpRadioButton = new System.Windows.Forms.RadioButton();
			this.SuspendLayout();
			// 
			// cancelButton
			// 
			this.cancelButton.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right);
			this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
			this.cancelButton.Location = new System.Drawing.Point(527, 137);
			this.cancelButton.Name = "cancelButton";
			this.cancelButton.TabIndex = 4;
			this.cancelButton.Text = "Cancel";
			this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
			// 
			// okButton
			// 
			this.okButton.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right);
			this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
			this.okButton.Location = new System.Drawing.Point(444, 137);
			this.okButton.Name = "okButton";
			this.okButton.TabIndex = 3;
			this.okButton.Text = "OK";
			this.okButton.Click += new System.EventHandler(this.okButton_Click);
			// 
			// loggingRadioButton
			// 
			this.loggingRadioButton.Anchor = ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right);
			this.loggingRadioButton.Checked = true;
			this.loggingRadioButton.Location = new System.Drawing.Point(32, 48);
			this.loggingRadioButton.Name = "loggingRadioButton";
			this.loggingRadioButton.Size = new System.Drawing.Size(560, 24);
			this.loggingRadioButton.TabIndex = 0;
			this.loggingRadioButton.TabStop = true;
			this.loggingRadioButton.Text = "Creates a logging language from scratch that colorizes lines.  Perfect for an FTP" +
				" logging display.";
			// 
			// headingLabel
			// 
			this.headingLabel.Anchor = ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right);
			this.headingLabel.Location = new System.Drawing.Point(16, 16);
			this.headingLabel.Name = "headingLabel";
			this.headingLabel.Size = new System.Drawing.Size(576, 40);
			this.headingLabel.TabIndex = 4;
			this.headingLabel.Text = "SyntaxEditor allows for instant creation of languages.  Even multiple lanugages m" +
				"ay be linked together.  The following examples show a lot of this dynamic functi" +
				"onality.";
			// 
			// directiveXmlToCSharpRadioButton
			// 
			this.directiveXmlToCSharpRadioButton.Anchor = ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right);
			this.directiveXmlToCSharpRadioButton.Location = new System.Drawing.Point(32, 72);
			this.directiveXmlToCSharpRadioButton.Name = "directiveXmlToCSharpRadioButton";
			this.directiveXmlToCSharpRadioButton.Size = new System.Drawing.Size(560, 24);
			this.directiveXmlToCSharpRadioButton.TabIndex = 1;
			this.directiveXmlToCSharpRadioButton.Text = "Loads the XML language definition and transitions to C# code inside a <% %> scope" +
				"s.";
			// 
			// scriptXmlToCSharpRadioButton
			// 
			this.scriptXmlToCSharpRadioButton.Anchor = ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right);
			this.scriptXmlToCSharpRadioButton.Location = new System.Drawing.Point(32, 96);
			this.scriptXmlToCSharpRadioButton.Name = "scriptXmlToCSharpRadioButton";
			this.scriptXmlToCSharpRadioButton.Size = new System.Drawing.Size(560, 24);
			this.scriptXmlToCSharpRadioButton.TabIndex = 2;
			this.scriptXmlToCSharpRadioButton.Text = "Loads the XML language definition and transitions to C# code inside a script tag " +
				"block";
			// 
			// DynamicallyCreateForm
			// 
			this.AcceptButton = this.okButton;
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.CancelButton = this.cancelButton;
			this.ClientSize = new System.Drawing.Size(610, 168);
			this.Controls.AddRange(new System.Windows.Forms.Control[] {
																		  this.scriptXmlToCSharpRadioButton,
																		  this.directiveXmlToCSharpRadioButton,
																		  this.loggingRadioButton,
																		  this.headingLabel,
																		  this.okButton,
																		  this.cancelButton});
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
			this.MaximizeBox = false;
			this.MinimizeBox = false;
			this.Name = "DynamicallyCreateForm";
			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
			this.Text = "Dynamic Language Creation";
			this.ResumeLayout(false);

		}
		#endregion

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// EVENT HANDLERS
		/////////////////////////////////////////////////////////////////////////////////////////////////////

		/// <summary>
		/// Occurs when the button is clicked.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">Event arguments.</param>
		private void cancelButton_Click(object sender, System.EventArgs e) {
			// Close the form
			this.Close();
		}

		/// <summary>
		/// Occurs when the button is clicked.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">Event arguments.</param>
		private void okButton_Click(object sender, System.EventArgs e) {
			if (loggingRadioButton.Checked)
				this.CreateLoggingLanguage();
			else if (directiveXmlToCSharpRadioButton.Checked)
				this.CreateDirectiveXmlToCSharpLanguage();
			else if (scriptXmlToCSharpRadioButton.Checked)
				this.CreateScriptXmlToCSharpLanguage();

			// Close the form
			this.Close();
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// NON-PUBLIC PROCEDURES
		/////////////////////////////////////////////////////////////////////////////////////////////////////
		
		/// <summary>
		/// Loads two languages and creates a state transition from XML to C# within ASP-style directives.
		/// </summary>
		private void CreateDirectiveXmlToCSharpLanguage() {
			// Load the two languages
            WindowsApplicationContext winContext = new WindowsApplicationContext();
			language = DynamicSyntaxLanguage.LoadFromXml(winContext.DynamicLexersPath + "ActiproSoftware.XML.xml", 0);
            DynamicSyntaxLanguage cSharpLanguage = DynamicSyntaxLanguage.LoadFromXml(winContext.DynamicLexersPath + "ActiproSoftware.CSharp.xml", 0);

			// Update the example text
			language.ExampleText = "<tagblock>\r\n" +
				"\t<!-- This ASP-style directive block transitions to C# language -->\r\n" +
				"\t<%\r\n" +
				"\t\t// C# comment\r\n" +
				"\t\tfor (int i = 0; i < 10; i++) {\r\n" +
				"\t\t}\r\n" +
				"\t%>\r\n" +
				"</tagblock>\r\n";

			// Mark that updating is starting
			language.IsUpdating = true;
			cSharpLanguage.IsUpdating = true;

			// Add a highlighting style
			language.HighlightingStyles.Add(new HighlightingStyle("ASPDirectiveDelimiterStyle", null, Color.Black, Color.Yellow));

			// Create a new lexical state
			DynamicLexicalState lexicalState = new DynamicLexicalState(0, "ASPDirectiveState");
			lexicalState.DefaultTokenKey = "ASPDirectiveDefaultToken";
			lexicalState.DefaultHighlightingStyle = language.HighlightingStyles["DefaultStyle"];
			lexicalState.LexicalStateTransitionLexicalState = cSharpLanguage.LexicalStates["DefaultState"];
			language.LexicalStates.Add(lexicalState);

			// Add the new lexical state at the beginning of the child states...
			// Remember that with an NFA regular expression, the first match is taken...
			// So since a < scope pattern is already in place, we must insert the new one before it
			language.LexicalStates["DefaultState"].ChildLexicalStates.Insert(0, lexicalState);

			// Create a lexical scope with a lexical state transition
			DynamicLexicalScope lexicalScope = new DynamicLexicalScope();
			lexicalState.LexicalScopes.Add(lexicalScope);
			lexicalScope.StartLexicalPatternGroup = 
				new LexicalPatternGroup(LexicalPatternType.Explicit, "ASPDirectiveStartToken", 
					language.HighlightingStyles["ASPDirectiveDelimiterStyle"], @"<%");
			lexicalScope.EndLexicalPatternGroup = 
				new LexicalPatternGroup(LexicalPatternType.Explicit, "ASPDirectiveEndToken", 
					language.HighlightingStyles["ASPDirectiveDelimiterStyle"], @"%>");

			// Mark that updating is complete (since linking is complete, the flag setting 
			//   will filter from the XML language into the C# language)
			language.IsUpdating = false;
		}
		
		/// <summary>
		/// Loads two languages and creates a state transition from XML to C# within <c>style</c> tags.
		/// </summary>
		private void CreateScriptXmlToCSharpLanguage() {
			// Load the two languages
            WindowsApplicationContext winContext = new WindowsApplicationContext();
            language = DynamicSyntaxLanguage.LoadFromXml(winContext.DynamicLexersPath + "ActiproSoftware.XML.xml", 0);
            DynamicSyntaxLanguage cSharpLanguage = DynamicSyntaxLanguage.LoadFromXml(winContext.DynamicLexersPath + "ActiproSoftware.CSharp.xml", 0);

			// Update the example text
			language.ExampleText = "<tagblock>\r\n" +
				"\t<!-- This script block transitions to C# language -->\r\n" +
				"\t<script>\r\n" +
				"\t\t// C# comment\r\n" +
				"\t\tfor (int i = 0; i < 10; i++) {\r\n" +
				"\t\t}\r\n" +
				"\t</script>\r\n" +
				"</tagblock>\r\n";

			// Mark that updating is starting
			language.IsUpdating = true;
			cSharpLanguage.IsUpdating = true;

			// Create a new lexical state
			DynamicLexicalState lexicalState = new DynamicLexicalState(0, "ScriptStartTagState");
			lexicalState.DefaultTokenKey = "ScriptStartTagDefaultToken";
			lexicalState.DefaultHighlightingStyle = language.HighlightingStyles["TagNameStyle"];
			lexicalState.ChildLexicalStates.Add(language.LexicalStates["StartTagAttributeState"]);
			language.LexicalStates.Add(lexicalState);

			// Add the new lexical state at the beginning of the child states...
			// Remember that with an NFA regular expression, the first match is taken...
			// So since a < scope pattern is already in place, we must insert the new one before it
			language.LexicalStates["DefaultState"].ChildLexicalStates.Insert(0, lexicalState);

			// Create a lexical scope with a lexical state transition
			DynamicLexicalScope lexicalScope = new DynamicLexicalScope();
			lexicalState.LexicalScopes.Add(lexicalScope);
			lexicalScope.StartLexicalPatternGroup = new LexicalPatternGroup(LexicalPatternType.Explicit, "StartTagStartToken", 
					language.HighlightingStyles["TagDelimiterStyle"], @"<", "script");
			lexicalScope.EndLexicalPatternGroup = new LexicalPatternGroup(LexicalPatternType.Regex, "StartTagEndToken", 
					language.HighlightingStyles["TagDelimiterStyle"], @"/? >");
			DynamicLexicalScope transitionLexicalScope = new DynamicLexicalScope();
			transitionLexicalScope.EndLexicalPatternGroup = new LexicalPatternGroup(LexicalPatternType.Explicit, "EndTagStartToken", 
					language.HighlightingStyles["TagDelimiterStyle"], @"</", "script");
			lexicalScope.LexicalStateTransition = new LexicalScopeLexicalStateTransition(cSharpLanguage.LexicalStates["DefaultState"], transitionLexicalScope);

			// Mark that updating is complete (since linking is complete, the flag setting 
			//   will filter from the XML language into the C# language)
			language.IsUpdating = false;
		}
		
		/// <summary>
		/// Creates a logging language from scratch.
		/// </summary>
		private void CreateLoggingLanguage() {
			// Create a language
			language = new DynamicSyntaxLanguage("Logging", false);
			language.ExampleText = "This is a regular text message.\r\n" +
				"INFO   : This is a sample info message.\r\n" +
				"WARNING: This is a sample warning.\r\n" +
				"ERROR  : This is a sample error.\r\n";

			// Set the highlighting styles
			HighlightingStyle defaultHighlightingStyle = language.HighlightingStyles["DefaultStyle"];
			language.HighlightingStyles.Add(new HighlightingStyle("InfoMessageDelimiterStyle", null, Color.DarkGreen, Color.Empty));
			language.HighlightingStyles.Add(new HighlightingStyle("InfoMessageDefaultStyle", null, Color.Green, Color.Empty));
			language.HighlightingStyles.Add(new HighlightingStyle("WarningMessageDelimiterStyle", null, Color.DarkBlue, Color.Empty));
			language.HighlightingStyles.Add(new HighlightingStyle("WarningMessageDefaultStyle", null, Color.Blue, Color.Empty));
			language.HighlightingStyles.Add(new HighlightingStyle("ErrorMessageDelimiterStyle", null, Color.DarkRed, Color.Empty));
			language.HighlightingStyles.Add(new HighlightingStyle("ErrorMessageDefaultStyle", null, Color.Red, Color.Empty));
			language.HighlightingStyles["InfoMessageDelimiterStyle"].Bold = ActiproSoftware.ComponentModel.DefaultableBoolean.True;
			language.HighlightingStyles["WarningMessageDelimiterStyle"].Bold = ActiproSoftware.ComponentModel.DefaultableBoolean.True;
			language.HighlightingStyles["ErrorMessageDelimiterStyle"].Bold = ActiproSoftware.ComponentModel.DefaultableBoolean.True;

			// Create an info message state
			DynamicLexicalState infoMessageLexicalState = new DynamicLexicalState(0, "InfoMessageState");
			infoMessageLexicalState.DefaultTokenKey = "InfoMessageDefaultToken";
			infoMessageLexicalState.DefaultHighlightingStyle = language.HighlightingStyles["InfoMessageDefaultStyle"];
			DynamicLexicalScope lexicalScope = new DynamicLexicalScope();
			infoMessageLexicalState.LexicalScopes.Add(lexicalScope);
			lexicalScope.StartLexicalPatternGroup = new LexicalPatternGroup(LexicalPatternType.Regex, "InfoMessageStartToken", 
					language.HighlightingStyles["InfoMessageDelimiterStyle"], @"^INFO \s* :");
			lexicalScope.EndLexicalPatternGroup = new LexicalPatternGroup(LexicalPatternType.Regex, "InfoMessageEndToken", 
					language.HighlightingStyles["InfoMessageDelimiterStyle"], @"{LineTerminatorMacro}");
			language.LexicalStates.Add(infoMessageLexicalState);

			// Create a warning message state
			DynamicLexicalState warningMessageLexicalState = new DynamicLexicalState(0, "WarningMessageState");
			warningMessageLexicalState.DefaultTokenKey = "WarningMessageDefaultToken";
			warningMessageLexicalState.DefaultHighlightingStyle = language.HighlightingStyles["WarningMessageDefaultStyle"];
			lexicalScope = new DynamicLexicalScope();
			warningMessageLexicalState.LexicalScopes.Add(lexicalScope);
			lexicalScope.StartLexicalPatternGroup = new LexicalPatternGroup(LexicalPatternType.Regex, "WarningMessageStartToken", 
					language.HighlightingStyles["WarningMessageDelimiterStyle"], @"^WARNING \s* :");
			lexicalScope.EndLexicalPatternGroup = new LexicalPatternGroup(LexicalPatternType.Regex, "WarningMessageEndToken", 
					language.HighlightingStyles["WarningMessageDelimiterStyle"], @"{LineTerminatorMacro}");
			language.LexicalStates.Add(warningMessageLexicalState);

			// Create an error message state
			DynamicLexicalState errorMessageLexicalState = new DynamicLexicalState(0, "ErrorMessageState");
			errorMessageLexicalState.DefaultTokenKey = "ErrorMessageDefaultToken";
			errorMessageLexicalState.DefaultHighlightingStyle = language.HighlightingStyles["ErrorMessageDefaultStyle"];
			lexicalScope = new DynamicLexicalScope();
			errorMessageLexicalState.LexicalScopes.Add(lexicalScope);
			lexicalScope.StartLexicalPatternGroup = new LexicalPatternGroup(LexicalPatternType.Regex, "ErrorMessageStartToken", 
					language.HighlightingStyles["ErrorMessageDelimiterStyle"], @"^ERROR \s* :");
			lexicalScope.EndLexicalPatternGroup = new LexicalPatternGroup(LexicalPatternType.Regex, "ErrorMessageEndToken", 
					language.HighlightingStyles["ErrorMessageDelimiterStyle"], @"{LineTerminatorMacro}");
			language.LexicalStates.Add(errorMessageLexicalState);

			// Create the default state
			DynamicLexicalState lexicalState = new DynamicLexicalState(0, "DefaultState");
			lexicalState.DefaultHighlightingStyle = defaultHighlightingStyle;
			lexicalState.ChildLexicalStates.Add(infoMessageLexicalState);
			lexicalState.ChildLexicalStates.Add(warningMessageLexicalState);
			lexicalState.ChildLexicalStates.Add(errorMessageLexicalState);
			language.LexicalStates.Add(lexicalState);
			language.DefaultLexicalState = lexicalState;

			// Mark that updating is complete
			language.IsUpdating = false;
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// PUBLIC PROCEDURES
		/////////////////////////////////////////////////////////////////////////////////////////////////////

		/// <summary>
		/// Gets the <see cref="SyntaxLanguage"/> that was created.
		/// </summary>
		/// <value>The <see cref="SyntaxLanguage"/> that was created.</value>
		public SyntaxLanguage Language {
			get {
				return language;
			}
		}
	}
}
